package org.fg.logcommon.config;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.net.SocketAppender;
import ch.qos.logback.classic.sift.MDCBasedDiscriminator;
import ch.qos.logback.classic.sift.SiftingAppender;
import ch.qos.logback.core.util.Duration;
import cn.hutool.core.util.StrUtil;
import com.fingard.luna.framework.base.multithread.ThreadContext;
import lombok.extern.slf4j.Slf4j;
import org.fg.logcommon.Constant;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Slf4j
public class HeaderCheckInterceptor implements HandlerInterceptor {

    private static final String HEADER_KEY = Constant.MDC_KEY;
    private static final String APPEND_NAME = "APPEND_NAME";
    private List<String> closedAppend = new ArrayList<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 清空 ThreadContext 防止上一次请求造成干扰
        ThreadContext.clearAttributes();
        // 检查请求头是否存在
        String mdc = request.getHeader(HEADER_KEY);
        if (StrUtil.isNotEmpty(mdc)) {
            // 请求头中存在 MDC   初始化一个uuid 作为本次请求的 append 名字（保证不重复）
            String value = UUID.randomUUID().toString();
            // 将 append 创建出来
            addAppend(value);
            MDC.put(Constant.MDC_KEY, mdc);
            ThreadContext.setNotInheritableAttribute(APPEND_NAME, value);
            ThreadContext.setNotInheritableAttribute(Constant.MDC_KEY, mdc);
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        MDC.remove(Constant.MDC_KEY);
        closeAppend(ThreadContext.getAttribute(APPEND_NAME));
        ThreadContext.removeAttribute(APPEND_NAME);
        ThreadContext.removeAttribute(Constant.MDC_KEY);
    }


    /**
     * 增加一个 Append
     */
    public void addAppend(String name) {
        if (StrUtil.isNotEmpty(name)) {
            LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
            Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
            SiftingAppender append = getAppend(name, lc);
            root.addAppender(append);
            ThreadContext.setInheritableAttribute("S_A", append);
        }
    }

    public void closeAppend(String name) {
        if (StrUtil.isNotEmpty(name)) {

            SocketAppender appender = ThreadContext.getAttribute("SOA_APPEND");
            if (appender != null) {
                closedAppend.add(appender.getName());
                log.info("关闭 appender {}", appender.getName());
                Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
                appender.clearAllFilters();
                appender.stop();
                root.detachAppender(appender);
                ThreadContext.removeAttribute("SOA_APPEND");
            }


            SiftingAppender append = ThreadContext.getAttribute("S_A");
            if (append != null) {
                Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
                append.clearAllFilters();
                append.stop();
                root.detachAppender(append);
                ThreadContext.removeAttribute("S_A");
            }
        }

    }

    private static SiftingAppender getAppend(String name, LoggerContext lc) {
        SiftingAppender siftingAppender = new SiftingAppender();
        MDCBasedDiscriminator discriminator = new MDCBasedDiscriminator();
        discriminator.setContext(lc);
        discriminator.setKey(Constant.MDC_KEY);
        discriminator.setDefaultValue("default");
        discriminator.start();
        siftingAppender.setDiscriminator(discriminator);
        siftingAppender.setName(name);
        siftingAppender.setContext(lc);
        siftingAppender.setMaxAppenderCount(10000);
        siftingAppender.setAppenderFactory((context, discriminatingValue) -> {
            SocketAppender appender = new SocketAppender();
            appender.setRemoteHost("127.0.0.1");
            appender.setPort(9977);
            appender.setContext(context);
            appender.setName(name + discriminatingValue);
            // 这个参数
            appender.setIncludeCallerData(true);
            appender.setQueueSize(10000);
            appender.setEventDelayLimit(Duration.buildBySeconds(10));
            appender.setReconnectionDelay(Duration.buildBySeconds(10));
            appender.start();
            ThreadContext.setInheritableAttribute("SOA_APPEND", appender);
            return appender;
        });
        siftingAppender.start();
        siftingAppender.setTimeout(Duration.buildBySeconds(10));
        DefaultDiscriminatorFilter defaultDiscriminatorFilter = new DefaultDiscriminatorFilter();
        defaultDiscriminatorFilter.setKey(Constant.MDC_KEY);
        defaultDiscriminatorFilter.setDefaultValue("default");
        defaultDiscriminatorFilter.start();
        siftingAppender.addFilter(defaultDiscriminatorFilter);
        return siftingAppender;
    }
}